﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Threading;
using System.Web;
using viBlog.Classes;
using viBlog.Providers;
using visinia.SmartEngine.Cache;

namespace viBlog.Controllers
{
    /// <summary>
    /// The controller for the blog posts comments
    /// </summary>
    public class CommentController
    {
        #region CACHE KEYS 
        private const string KEY_COMMENT = "viblogcomment_{0}";
        private const string KEY_All_COMMENTS = "viblogcommentsAll";
        private const string KEY_APPROVED_COMMENTS = "viblogcommentsApproved";
        private const string KEY_APPROVED_COMMENTS_BY_POST = "viblogcommentsByPost_{0}";
        #endregion

        /// <summary>
        /// Gets all the comments approved and un approved but for only admin role members
        /// </summary>              
        public static List<Comment> GetCommentsAdmin()
        {
            if (Thread.CurrentPrincipal.IsInRole("admin"))
            {
                string key = string.Format(KEY_All_COMMENTS);
                List<Comment> list = (List<Comment>)DataCache.GetCache(key);
                if (list == null)
                {
                    list = FillComments(viBlogDataProvider.Provider.GetCommentsAdmin());
                    DataCache.SetCache(key, list, new System.TimeSpan(0, 20, 0));
                }
                return list;
            }
            return null;
        }

        /// <summary>
        /// Gets all the unapproved comments but for only admin role members
        /// </summary>                
        public static List<Comment> GetPendingCommentsAdmin()
        {
            return GetCommentsAdmin().FindAll(c => (c.Status == Comment.CommentStatus.Pending));
        }

        /// <summary>
        /// Gets all the approved comments but for only admin role members
        /// </summary>                
        public static List<Comment> GetApprovedCommentsAdmin()
        {
            return GetCommentsAdmin().FindAll(c => (c.Status == Comment.CommentStatus.Approved));
        }

        /// <summary>
        /// Gets the approved/unapproved comment but for only admin role members
        /// </summary>                
        public static Comment GetCommentAdmin(int CommentId)
        {
            return GetCommentsAdmin().Find(c => c.CommentId == CommentId);
        }
        
        /// <summary>
        /// Gets the approved comment
        /// </summary>        
        /// <returns>The approved comment</returns>
        public static Comment GetComment(int CommentId)
        {
            string key = string.Format(KEY_COMMENT, CommentId);
            Comment comment = (Comment)DataCache.GetCache(key);
            if (comment == null)
            {
                comment = FillComment(viBlogDataProvider.Provider.GetComment(CommentId));
                DataCache.SetCache(key, comment);
            }
            return comment;           
        }

        internal static List<Comment> GetComments(List<int> CommentIds, int Count)
        {
            List<Comment> comments = new List<Comment>();
            foreach (int CommentId in CommentIds)
            {
                if (Count-- == 0)
                    break;
                comments.Add(GetComment(CommentId));
            }
            return comments;
        }

        /// <summary>
        /// Gets the comments count of the specified post
        /// </summary>
        /// <param name="PostId">The post id whose comment count to get</param>
        /// <returns>The count of the comments</returns>
        public static int GetCommentsCount(int PostId)
        {
            return GetCommentIdsByPost(PostId).Count;         
        }  
        
        /// <summary>
        /// Gets all the comment of a specified post
        /// </summary>
        /// <param name="PostId">The post whose comments to return</param>        
        /// <returns>The comments</returns>
        public static List<Comment> GetComments(int PostId)
        {
            return GetComments(GetCommentIdsByPost(PostId), GetCommentIdsByPost(PostId).Count);
        }

        private static List<int> GetCommentIdsByPost(int PostId)
        {
            string key = string.Format(KEY_APPROVED_COMMENTS_BY_POST, PostId);
            List<int> commentIds = (List<int>)DataCache.GetCache(key);
            if (commentIds == null)
            {
                commentIds = new List<int>();
                IDataReader dr = viBlogDataProvider.Provider.GetCommentsByPost(PostId);
                while (dr.Read())
                {
                    if (dr["CommentId"] != Convert.DBNull)
                        commentIds.Add((int)dr["CommentId"]);
                }
                dr.Close();
                DataCache.SetCache(key, commentIds, new TimeSpan(0, 20, 0));
            }
            return commentIds;
        }

        ///// <summary>
        ///// Gets all the approved comments
        ///// </summary>        
        ///// <returns>The approved comments</returns>
        //public static List<Comment> GetComments()
        //{
        //    return GetComments(CommentIdsAll(), CommentIdsAll().Count);
        //}

        private static List<int> CommentIdsAll()
        {
            string key = KEY_APPROVED_COMMENTS;
            List<int> commentIds = (List<int>)DataCache.GetCache(key);
            if (commentIds == null)
            {
                commentIds = new List<int>();
                IDataReader dr = viBlogDataProvider.Provider.GetComments();
                while (dr.Read())
                {
                    if (dr["CommentId"] != Convert.DBNull)
                        commentIds.Add((int)dr["CommentId"]);
                }
                dr.Close();
                DataCache.SetCache(key, commentIds, new TimeSpan(0, 20, 0));
            }
            return commentIds;
        }

        
        /// <summary>
        /// Gets the recent posted comments
        /// </summary>
        /// <param name="Count">Count of comments to return</param>
        /// <returns>The list of comments</returns>
        public static List<Comment> GetRecentComments(int Count)
        {
            return GetComments(CommentIdsAll(), Count);
        }

        #region DATA
        /// <summary>
        /// Adds a new comment
        /// </summary>
        /// <param name="comment"></param>
        public static int AddComment(Comment comment)
        {
            IDataReader dr = viBlogDataProvider.Provider.AddComment(comment.PostId, comment.Author, comment.Email, comment.Website, comment.Date, comment.Content, comment.Status);            
            int index = 0;
            while (dr.Read())
            {
                if (dr[0] != Convert.DBNull)
                    index = (int)dr[0];
            }
            dr.Close();
            DataCache.DeleteCacheMultiple("viblogcomment");
            return index;
        }

        /// <summary>
        /// Updates a comment
        /// </summary>        
        public static void UpdateComment(Comment comment)
        {
            viBlogDataProvider.Provider.UpdateComment(comment.CommentId, comment.PostId, comment.Author, comment.Email, comment.Website, comment.Date, comment.Content, comment.Status);
            DataCache.DeleteCacheMultiple("viblogcomment");
        }

        /// <summary>
        /// Deletes a comment
        /// </summary>
        /// <param name="CommentId"></param>
        public static void DeleteComment(int CommentId)
        {
            viBlogDataProvider.Provider.DeleteComment(CommentId);
            DataCache.DeleteCacheMultiple("viblogcomment");
        }
        
        /// <summary>
        /// Deletes all the comments for the specified post
        /// </summary>
        /// <param name="PostId"></param>
        public static void DeleteComments(int PostId)
        {
            viBlogDataProvider.Provider.DeleteComments(PostId);
            DataCache.DeleteCacheMultiple("viblogcomment");
        }
        #endregion

        #region HELPERS
        private static Comment FillComment(IDataReader dr)
        {
            while (dr.Read())
            {
                return ActualRead(dr, true);
            }
            return null;
        }
        private static List<Comment> FillComments(IDataReader dr)
        {
            List<Comment> list = new List<Comment>();
            while (dr.Read())
            {
                list.Add(ActualRead(dr, false));
            }
            dr.Close();
            return list;
        }

        private static Comment ActualRead(IDataReader dr, bool CloseDataReader)
        {
            Comment comment = new Comment();
            if (dr["CommentId"] != Convert.DBNull)
                comment.CommentId = (int)dr["CommentId"];
            if (dr["PostId"] != Convert.DBNull)
                comment.PostId = (int)dr["PostId"];            
            if (dr["Author"] != Convert.DBNull)
                comment.Author = HttpUtility.HtmlEncode((string)dr["Author"]);
            if (dr["Email"] != Convert.DBNull)
                comment.Email = (string)dr["Email"];
            if (dr["Website"] != Convert.DBNull)
                comment.Website = (string)dr["Website"];
            if (dr["Date"] != Convert.DBNull)
                comment.Date = (DateTime)dr["Date"];
            if (dr["CommentContent"] != Convert.DBNull)
                comment.Content = HttpUtility.HtmlEncode((string)dr["CommentContent"]);
            if (dr["Status"] != Convert.DBNull)
                comment.Status = (Comment.CommentStatus)dr["Status"];

            Post post = PostController.GetPost(comment.PostId);
            if (post == null)
                comment.Url = null;           
            comment.Url = post.Url + "#Comment-" + comment.CommentId;                   
            if (CloseDataReader)
                dr.Close();
            return comment;
        }
        #endregion
    }
}
